class Base64 {
    constructor() {
        /*
     *  byte数组表示成对应的16进制字符串
     *  <li>    方便后续的解析
     *  <li>    这是保证byte是8位而不是32的有效方式
     */
        this.hex_ = new Map();
        this.hex_.set(0, '0');
        this.hex_.set(1, '1');
        this.hex_.set(2, '2');
        this.hex_.set(3, '3');
        this.hex_.set(4, '4');
        this.hex_.set(5, '5');
        this.hex_.set(6, '6');
        this.hex_.set(7, '7');
        this.hex_.set(8, '8');
        this.hex_.set(9, '9');
        this.hex_.set(10, 'A');
        this.hex_.set(11, 'B');
        this.hex_.set(12, 'C');
        this.hex_.set(13, 'D');
        this.hex_.set(14, 'E');
        this.hex_.set(15, 'F');
        //  逆向保存
        this.hex_1 = new Map();
        this.hex_1.set('0', 0);
        this.hex_1.set('1', 1);
        this.hex_1.set('2', 2);
        this.hex_1.set('3', 3);
        this.hex_1.set('4', 4);
        this.hex_1.set('5', 5);
        this.hex_1.set('6', 6);
        this.hex_1.set('7', 7);
        this.hex_1.set('8', 8);
        this.hex_1.set('9', 9);
        this.hex_1.set('A', 10);
        this.hex_1.set('B', 11);
        this.hex_1.set('C', 12);
        this.hex_1.set('D', 13);
        this.hex_1.set('E', 14);
        this.hex_1.set('F', 15);
        /*
     *  base64使用的字符为(顺序)
     *  <li>    A-Z
     *  <li>    a-z
     *  <li>    0-9
     *  <li>    +/
     *
     *  <li>    占位符(补位符) =
     */
        this.origin = [
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', "P", 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', "p", 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
            '+', "/", '='
        ]
        /*
             *  使用map表逆向保存索引
             */
        this.map_ = new Map();
        let i_ = 0;
        for (let x of this.origin) {
            this.map_.set(x, i_++);
        }
    }
    /*
     *  字符串转byte数组
     *  <li>    里面存储的是int
     *  <li>    直接使用 需要注意只去最后8位即可
     *  <li>    这里只对utf-8字符串进行操作
     */
    getBytes(s) {
        let rtn = [];
        let b1 = 0xe0;
        let b2 = 0x80;
        let t = 0x3f;
        let len = s.length;
        for (let x = 0; x < len; x++) {
            let c = s.charCodeAt(x);
            if (((c >> 8) & 0xff) != 0) {
                rtn.push((b1 | (c >> 12)) & 0xff)
                rtn.push((b2 | ((c >> 6) & t)) & 0xff)
                rtn.push((b2 | ((c) & t)) & 0xff)
            } else {
                rtn.push(c);
            }
        }
        return rtn;
    }
    bytesToString(bytes) {
        let rtn_ = [];
        if (bytes == null || bytes.length == 0) {
            return '';
        }
        let index = 0;
        let len = bytes.length;
        while (index < len) {
            let a = bytes[index++];
            let d = null;
            if ((a >> 7) == 1) {
                let b = bytes[index++];
                let c = bytes[index++];
                let e = 0;
                let t = 0;
                e = a & 0x0f;
                e = e << 6;
                t = b & 0x3f
                e = e | t;
                t = c & 0x3f;
                e = e << 6;
                e = e | t;
                d = String.fromCharCode(e);
            } else {
                d = String.fromCharCode(a);
            }
            rtn_.push(d);
        }
        //console.log(rtn_.join(''))
        return rtn_.join('');
    }
    bytesToHex(bytes) {
        let result_ = [];
        for (let x of bytes) {
            let a1 = x >> 4;
            let a2 = x & 0x0f;
            result_.push(this.hex_.get(a1))
            result_.push(this.hex_.get(a2))
        }
        return result_.join('');
    }
    hexToByte(s) {
        let len = s.length;
        let index = 0;
        let result_ = [];
        while (index < len) {
            let a1 = this.hex_1.get(s.charAt(index++));
            let a2 = this.hex_1.get(s.charAt(index++));
            let v = (a1 << 4) | a2;
            result_.push(v)
        }
        return result_;
    }
    encode(s) {
        let bytes = this.getBytes(s);
        let len = bytes.length;
        let count = Math.floor(len / 3);
        let rest = len % 3;
        let index = 0;
        //  中间产物(直接结果)
        let result_0 = [];
        for (let i = 0; i < count; i++) {
            let a1 = bytes[index++];
            let a2 = bytes[index++];
            let a3 = bytes[index++];
            let b1 = (a1 & 0xfc) >> 2;
            let b2 = ((a1 & 0x03) << 4) | ((a2 & 0xf0) >> 4);
            let b3 = ((a2 & 0x0f) << 2) | ((a3 & 0xc0) >> 6);
            let b4 = a3 & 0x3f;
            result_0.push(this.origin[b1])
            result_0.push(this.origin[b2])
            result_0.push(this.origin[b3])
            result_0.push(this.origin[b4])
        }
        if (rest == 1) {
            let a1 = bytes[index++];
            let b1 = (a1 & 0xfc) >> 2;
            let b2 = ((a1 & 0x03) << 4);
            result_0.push(this.origin[b1])
            result_0.push(this.origin[b2])
            result_0.push(this.origin[64])
            result_0.push(this.origin[64])
        } else if (rest == 2) {
            let a1 = bytes[index++];
            let a2 = bytes[index++];
            let b1 = (a1 & 0xfc) >> 2;
            let b2 = ((a1 & 0x03) << 4) | ((a2 & 0xf0) >> 4);
            let b3 = ((a2 & 0x0f) << 2);
            result_0.push(this.origin[b1])
            result_0.push(this.origin[b2])
            result_0.push(this.origin[b3])
            result_0.push(this.origin[64])
        }
        return result_0.join('');
    }
    /*
         *  base64解码
         */
    decode(s) {
        let len = s.length;
        if (len % 4 != 0) {
            throw new Error('base64编码字符串无效')
        }
        let index = 0;
        let result_ = [];
        while (index < len) {
            let b1 = this.map_.get(s.charAt(index++));
            let b2 = this.map_.get(s.charAt(index++));
            let b3 = this.map_.get(s.charAt(index++));
            let b4 = this.map_.get(s.charAt(index++));
            if (b3 == 64) {
                let a1 = (b1 << 2) | ((b2 & 0x30) >> 4);
                result_.push(a1);
            } else if (b4 == 64) {
                let a1 = (b1 << 2) | ((b2 & 0x30) >> 4);
                let a2 = ((b2 & 0x0f) << 4) | ((b3 & 0x3c) >> 2);
                result_.push(a1);
                result_.push(a2);
            } else {
                let a1 = (b1 << 2) | ((b2 & 0x30) >> 4);
                let a2 = ((b2 & 0x0f) << 4) | ((b3 & 0x3c) >> 2);
                let a3 = ((b3 & 0x03) << 6) | (b4 & 0x3f);
                result_.push(a1);
                result_.push(a2);
                result_.push(a3);
            }
        }
        return this.bytesToString(result_);
    }
    /*
     *  将bytes转换成二进制字符串
     *  <li>    方便测试
     */
    toBinaryString(bytes) {
        let s_ = [];
        for (let x of bytes) {
            let child_ = [];
            for (let i = 7; i >= 0; i--) {
                if (((x >> i) & 0x01) == 1) {
                    child_.push(1);
                } else {
                    child_.push(0);
                }
            }
            s_.push(child_.join(''));
        }
        return s_.join(',')
    }
}
let base64 = new Base64();
export default base64
